package com.zhucan.tenant.mongo;

import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.zhucan.tenant.mongo.extension.MongoTenantDatabaseNameGenerator;
import com.zhucan.tenant.mongo.extension.MongoTenantProperties;
import com.zhucan.tenant.mongo.extension.TenantProvider;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mongo.MongoClientFactory;
import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.autoconfigure.mongo.MongoPropertiesClientSettingsBuilderCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.core.MongoDatabaseFactorySupport;

import java.util.stream.Collectors;

/**
 * @author My Lord zhuCan
 * @description 多租户的mongo自动装配
 * @since 2022-12-09 11:46
 **/
@ConditionalOnProperty(prefix = "tenant.mongodb", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnBean(value = {TenantProvider.class})
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({MongoClient.class})
@EnableConfigurationProperties({MongoTenantProperties.class, MongoProperties.class})
public class TenantMongoAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(MongoContextHolder.class)
    public MongoContextHolder mongoContextHolder(MongoTenantDatabaseNameGenerator generator,
                                                 TenantProvider provider) {
        return new MongoContextHolder.DefaultMongoContextHolder(generator, provider);
    }


    @Bean
    @ConditionalOnMissingBean(MongoTenantDatabaseNameGenerator.class)
    public MongoTenantDatabaseNameGenerator mongoTenantDatabaseNameGenerator(Environment environment,
                                                                             MongoTenantProperties mongoTenantProperties,
                                                                             MongoProperties mongoProperties) {
        return new MongoTenantDatabaseNameGenerator.DefaultMongoTenantDatabaseNameGenerator(environment, mongoTenantProperties, mongoProperties);
    }


    @Bean
    public MongoDatabaseFactorySupport<?> mongoDatabaseFactorySupport(MongoClient client,
                                                                      MongoProperties properties,
                                                                      MongoContextHolder contextHolder) {
        return new MongoMultiTenantFactory(client, properties.getDatabase(), contextHolder);
    }

    @Bean
    @ConditionalOnMissingBean({MongoClient.class})
    public MongoClient mongo(ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers,
                             MongoClientSettings settings) {
        return (new MongoClientFactory(builderCustomizers.orderedStream().collect(Collectors.toList()))).createMongoClient(settings);
    }

    @Configuration(
            proxyBeanMethods = false
    )
    @ConditionalOnMissingBean({MongoClientSettings.class})
    static class MongoClientSettingsConfiguration {
        MongoClientSettingsConfiguration() {
        }

        @Bean
        MongoClientSettings mongoClientSettings() {
            return MongoClientSettings.builder().build();
        }

        @Bean
        MongoPropertiesClientSettingsBuilderCustomizer mongoPropertiesCustomizer(MongoProperties properties,
                                                                                 Environment environment) {
            return new MongoPropertiesClientSettingsBuilderCustomizer(properties, environment);
        }
    }


}
